package com.lifeverse.service;

import com.lifeverse.entity.GroupDecision;
import com.lifeverse.entity.LifeEntity;
import com.lifeverse.entity.LifeEntityGroup;
import com.lifeverse.exception.BusinessException;
import com.lifeverse.repository.GroupDecisionRepository;
import com.lifeverse.repository.LifeEntityGroupRepository;
import com.lifeverse.repository.LifeEntityRepository;
import com.lifeverse.util.JsonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 群体决策服务
 * 实现简化版的群体决策算法
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class GroupDecisionService {
    
    private final GroupDecisionRepository decisionRepository;
    private final LifeEntityGroupRepository groupRepository;
    private final LifeEntityRepository lifeEntityRepository;
    
    /**
     * 创建群体决策
     */
    @Transactional
    public GroupDecision createDecision(Long groupId, String title, String description,
                                       GroupDecision.DecisionType type, Long proposerId,
                                       List<String> options) {
        log.info("创建群体决策: groupId={}, title={}, type={}", groupId, title, type);
        
        LifeEntityGroup group = groupRepository.findById(groupId)
                .orElseThrow(() -> new BusinessException("群体不存在: " + groupId));
        
        LifeEntity proposer = lifeEntityRepository.findById(proposerId)
                .orElseThrow(() -> new BusinessException("提议者不存在: " + proposerId));
        
        // 检查提议者是否是群体成员
        if (!group.getMembers().contains(proposer)) {
            throw new BusinessException("提议者必须是群体成员");
        }
        
        GroupDecision decision = new GroupDecision();
        decision.setGroup(group);
        decision.setTitle(title);
        decision.setDescription(description);
        decision.setDecisionType(type);
        decision.setProposer(proposer);
        decision.setOptions(JsonUtils.toJson(options));
        decision.setProposedAt(LocalDateTime.now());
        
        // 设置默认截止时间（7天后）
        decision.setDeadline(LocalDateTime.now().plusDays(7));
        
        GroupDecision savedDecision = decisionRepository.save(decision);
        
        log.info("成功创建群体决策: id={}", savedDecision.getId());
        return savedDecision;
    }
    
    /**
     * 开始投票
     */
    @Transactional
    public GroupDecision startVoting(Long decisionId) {
        log.info("开始投票: decisionId={}", decisionId);
        
        GroupDecision decision = decisionRepository.findById(decisionId)
                .orElseThrow(() -> new BusinessException("决策不存在: " + decisionId));
        
        if (decision.getDecisionStatus() != GroupDecision.DecisionStatus.PROPOSED &&
            decision.getDecisionStatus() != GroupDecision.DecisionStatus.DISCUSSING) {
            throw new BusinessException("决策状态不允许开始投票");
        }
        
        decision.startVoting();
        GroupDecision savedDecision = decisionRepository.save(decision);
        
        log.info("成功开始投票: decisionId={}", decisionId);
        return savedDecision;
    }
    
    /**
     * 投票
     */
    @Transactional
    public GroupDecision vote(Long decisionId, Long voterId, VoteChoice choice, BigDecimal weight) {
        log.info("投票: decisionId={}, voterId={}, choice={}", decisionId, voterId, choice);
        
        GroupDecision decision = decisionRepository.findById(decisionId)
                .orElseThrow(() -> new BusinessException("决策不存在: " + decisionId));
        
        LifeEntity voter = lifeEntityRepository.findById(voterId)
                .orElseThrow(() -> new BusinessException("投票者不存在: " + voterId));
        
        // 检查投票者是否是群体成员
        if (!decision.getGroup().getMembers().contains(voter)) {
            throw new BusinessException("投票者必须是群体成员");
        }
        
        // 检查决策是否在投票状态
        if (decision.getDecisionStatus() != GroupDecision.DecisionStatus.VOTING) {
            throw new BusinessException("决策不在投票状态");
        }
        
        // 检查是否过期
        if (decision.isExpired()) {
            throw new BusinessException("决策已过期");
        }
        
        // 记录投票
        recordVote(decision, voter, choice, weight);
        
        // 更新投票统计
        updateVotingStatistics(decision);
        
        GroupDecision savedDecision = decisionRepository.save(decision);
        
        log.info("成功投票: decisionId={}, voterId={}, choice={}", decisionId, voterId, choice);
        return savedDecision;
    }
    
    /**
     * 结束投票并计算结果
     */
    @Transactional
    public GroupDecision endVoting(Long decisionId) {
        log.info("结束投票: decisionId={}", decisionId);
        
        GroupDecision decision = decisionRepository.findById(decisionId)
                .orElseThrow(() -> new BusinessException("决策不存在: " + decisionId));
        
        if (decision.getDecisionStatus() != GroupDecision.DecisionStatus.VOTING) {
            throw new BusinessException("决策不在投票状态");
        }
        
        decision.endVoting();
        GroupDecision savedDecision = decisionRepository.save(decision);
        
        log.info("成功结束投票: decisionId={}, result={}", decisionId, savedDecision.getDecisionStatus());
        return savedDecision;
    }
    
    /**
     * 简单投票算法（多数决）
     */
    public DecisionResult simpleMajorityVoting(Long decisionId) {
        GroupDecision decision = decisionRepository.findById(decisionId)
                .orElseThrow(() -> new BusinessException("决策不存在: " + decisionId));
        
        Map<String, Object> votingResults = getVotingResults(decision);
        
        int totalVotes = decision.getSupportVotes() + decision.getOpposeVotes() + decision.getAbstainVotes();
        
        DecisionResult result = new DecisionResult();
        result.setDecisionId(decisionId);
        result.setAlgorithmType("SIMPLE_MAJORITY");
        result.setTotalVotes(totalVotes);
        result.setSupportVotes(decision.getSupportVotes());
        result.setOpposeVotes(decision.getOpposeVotes());
        result.setAbstainVotes(decision.getAbstainVotes());
        result.setSupportRate(decision.getSupportRate());
        
        // 简单多数决：支持票数 > 反对票数
        result.setApproved(decision.getSupportVotes() > decision.getOpposeVotes());
        result.setConfidenceScore(calculateConfidenceScore(decision));
        
        return result;
    }
    
    /**
     * 权重投票算法
     */
    public DecisionResult weightedVoting(Long decisionId, Map<Long, BigDecimal> memberWeights) {
        GroupDecision decision = decisionRepository.findById(decisionId)
                .orElseThrow(() -> new BusinessException("决策不存在: " + decisionId));
        
        Map<String, Object> votingResults = getVotingResults(decision);
        
        BigDecimal totalWeight = BigDecimal.ZERO;
        BigDecimal supportWeight = BigDecimal.ZERO;
        BigDecimal opposeWeight = BigDecimal.ZERO;
        BigDecimal abstainWeight = BigDecimal.ZERO;
        
        // 计算权重投票结果
        for (Map.Entry<Long, BigDecimal> entry : memberWeights.entrySet()) {
            Long memberId = entry.getKey();
            BigDecimal weight = entry.getValue();
            
            // 获取该成员的投票选择（这里简化处理）
            VoteChoice choice = getMemberVoteChoice(votingResults, memberId);
            
            totalWeight = totalWeight.add(weight);
            
            switch (choice) {
                case SUPPORT:
                    supportWeight = supportWeight.add(weight);
                    break;
                case OPPOSE:
                    opposeWeight = opposeWeight.add(weight);
                    break;
                case ABSTAIN:
                    abstainWeight = abstainWeight.add(weight);
                    break;
            }
        }
        
        DecisionResult result = new DecisionResult();
        result.setDecisionId(decisionId);
        result.setAlgorithmType("WEIGHTED_VOTING");
        result.setTotalWeight(totalWeight);
        result.setSupportWeight(supportWeight);
        result.setOpposeWeight(opposeWeight);
        result.setAbstainWeight(abstainWeight);
        
        // 权重支持率
        BigDecimal weightedSupportRate = totalWeight.compareTo(BigDecimal.ZERO) > 0 
                ? supportWeight.divide(totalWeight, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100))
                : BigDecimal.ZERO;
        result.setWeightedSupportRate(weightedSupportRate);
        
        // 权重投票：支持权重 > 反对权重
        result.setApproved(supportWeight.compareTo(opposeWeight) > 0);
        result.setConfidenceScore(calculateWeightedConfidenceScore(supportWeight, opposeWeight, totalWeight));
        
        return result;
    }
    
    /**
     * 共识算法（需要一致同意）
     */
    public DecisionResult consensusAlgorithm(Long decisionId) {
        GroupDecision decision = decisionRepository.findById(decisionId)
                .orElseThrow(() -> new BusinessException("决策不存在: " + decisionId));
        
        DecisionResult result = new DecisionResult();
        result.setDecisionId(decisionId);
        result.setAlgorithmType("CONSENSUS");
        result.setTotalVotes(decision.getParticipantsCount());
        result.setSupportVotes(decision.getSupportVotes());
        result.setOpposeVotes(decision.getOpposeVotes());
        result.setAbstainVotes(decision.getAbstainVotes());
        
        // 共识算法：没有反对票且有足够的支持票
        boolean hasConsensus = decision.getOpposeVotes() == 0 && 
                              decision.getSupportVotes() >= (decision.getGroup().getMemberCount() * 0.6);
        
        result.setApproved(hasConsensus);
        result.setConfidenceScore(hasConsensus ? BigDecimal.valueOf(95) : BigDecimal.valueOf(20));
        
        return result;
    }
    
    /**
     * 超级多数算法（需要2/3以上支持）
     */
    public DecisionResult superMajorityAlgorithm(Long decisionId) {
        GroupDecision decision = decisionRepository.findById(decisionId)
                .orElseThrow(() -> new BusinessException("决策不存在: " + decisionId));
        
        DecisionResult result = new DecisionResult();
        result.setDecisionId(decisionId);
        result.setAlgorithmType("SUPER_MAJORITY");
        result.setTotalVotes(decision.getParticipantsCount());
        result.setSupportVotes(decision.getSupportVotes());
        result.setOpposeVotes(decision.getOpposeVotes());
        result.setAbstainVotes(decision.getAbstainVotes());
        result.setSupportRate(decision.getSupportRate());
        
        // 超级多数：支持率 >= 66.67%
        boolean hasSuperMajority = decision.getSupportRate().compareTo(BigDecimal.valueOf(66.67)) >= 0;
        
        result.setApproved(hasSuperMajority);
        result.setConfidenceScore(calculateConfidenceScore(decision));
        
        return result;
    }
    
    /**
     * 记录投票
     */
    private void recordVote(GroupDecision decision, LifeEntity voter, VoteChoice choice, BigDecimal weight) {
        Map<String, Object> votingResults = getVotingResults(decision);
        
        // 记录投票者的选择
        Map<String, Object> voteRecord = new HashMap<>();
        voteRecord.put("voterId", voter.getId());
        voteRecord.put("voterName", voter.getName());
        voteRecord.put("choice", choice.name());
        voteRecord.put("weight", weight);
        voteRecord.put("timestamp", LocalDateTime.now());
        
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> votes = (List<Map<String, Object>>) votingResults.getOrDefault("votes", new ArrayList<>());
        votes.add(voteRecord);
        votingResults.put("votes", votes);
        
        decision.setVotingResults(JsonUtils.toJson(votingResults));
    }
    
    /**
     * 更新投票统计
     */
    private void updateVotingStatistics(GroupDecision decision) {
        Map<String, Object> votingResults = getVotingResults(decision);
        
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> votes = (List<Map<String, Object>>) votingResults.getOrDefault("votes", new ArrayList<>());
        
        int supportVotes = 0;
        int opposeVotes = 0;
        int abstainVotes = 0;
        
        for (Map<String, Object> vote : votes) {
            String choice = (String) vote.get("choice");
            switch (choice) {
                case "SUPPORT":
                    supportVotes++;
                    break;
                case "OPPOSE":
                    opposeVotes++;
                    break;
                case "ABSTAIN":
                    abstainVotes++;
                    break;
            }
        }
        
        decision.setParticipantsCount(votes.size());
        decision.setSupportVotes(supportVotes);
        decision.setOpposeVotes(opposeVotes);
        decision.setAbstainVotes(abstainVotes);
        decision.calculateSupportRate();
    }
    
    /**
     * 获取投票结果
     */
    private Map<String, Object> getVotingResults(GroupDecision decision) {
        if (decision.getVotingResults() == null) {
            return new HashMap<>();
        }
        return JsonUtils.fromJson(decision.getVotingResults(), Map.class);
    }
    
    /**
     * 获取成员投票选择
     */
    private VoteChoice getMemberVoteChoice(Map<String, Object> votingResults, Long memberId) {
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> votes = (List<Map<String, Object>>) votingResults.getOrDefault("votes", new ArrayList<>());
        
        for (Map<String, Object> vote : votes) {
            if (memberId.equals(vote.get("voterId"))) {
                String choice = (String) vote.get("choice");
                return VoteChoice.valueOf(choice);
            }
        }
        
        return VoteChoice.ABSTAIN; // 默认弃权
    }
    
    /**
     * 计算置信度评分
     */
    private BigDecimal calculateConfidenceScore(GroupDecision decision) {
        BigDecimal participationRate = decision.getParticipationRate();
        BigDecimal supportRate = decision.getSupportRate();
        
        // 置信度 = (参与率 * 0.3 + 支持率 * 0.7)
        return participationRate.multiply(BigDecimal.valueOf(0.3))
                .add(supportRate.multiply(BigDecimal.valueOf(0.7)))
                .setScale(2, RoundingMode.HALF_UP);
    }
    
    /**
     * 计算权重置信度评分
     */
    private BigDecimal calculateWeightedConfidenceScore(BigDecimal supportWeight, BigDecimal opposeWeight, BigDecimal totalWeight) {
        if (totalWeight.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.valueOf(50);
        }
        
        BigDecimal supportRate = supportWeight.divide(totalWeight, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
        BigDecimal margin = supportWeight.subtract(opposeWeight).divide(totalWeight, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
        
        // 置信度 = 支持率 + 边际优势 * 0.5
        return supportRate.add(margin.multiply(BigDecimal.valueOf(0.5)))
                .setScale(2, RoundingMode.HALF_UP);
    }
    
    /**
     * 投票选择枚举
     */
    public enum VoteChoice {
        SUPPORT("支持"),
        OPPOSE("反对"),
        ABSTAIN("弃权");
        
        private final String displayName;
        
        VoteChoice(String displayName) {
            this.displayName = displayName;
        }
        
        public String getDisplayName() {
            return displayName;
        }
    }
    
    /**
     * 决策结果类
     */
    public static class DecisionResult {
        private Long decisionId;
        private String algorithmType;
        private Integer totalVotes;
        private Integer supportVotes;
        private Integer opposeVotes;
        private Integer abstainVotes;
        private BigDecimal supportRate;
        private BigDecimal totalWeight;
        private BigDecimal supportWeight;
        private BigDecimal opposeWeight;
        private BigDecimal abstainWeight;
        private BigDecimal weightedSupportRate;
        private Boolean approved;
        private BigDecimal confidenceScore;
        
        // Getters and Setters
        public Long getDecisionId() { return decisionId; }
        public void setDecisionId(Long decisionId) { this.decisionId = decisionId; }
        
        public String getAlgorithmType() { return algorithmType; }
        public void setAlgorithmType(String algorithmType) { this.algorithmType = algorithmType; }
        
        public Integer getTotalVotes() { return totalVotes; }
        public void setTotalVotes(Integer totalVotes) { this.totalVotes = totalVotes; }
        
        public Integer getSupportVotes() { return supportVotes; }
        public void setSupportVotes(Integer supportVotes) { this.supportVotes = supportVotes; }
        
        public Integer getOpposeVotes() { return opposeVotes; }
        public void setOpposeVotes(Integer opposeVotes) { this.opposeVotes = opposeVotes; }
        
        public Integer getAbstainVotes() { return abstainVotes; }
        public void setAbstainVotes(Integer abstainVotes) { this.abstainVotes = abstainVotes; }
        
        public BigDecimal getSupportRate() { return supportRate; }
        public void setSupportRate(BigDecimal supportRate) { this.supportRate = supportRate; }
        
        public BigDecimal getTotalWeight() { return totalWeight; }
        public void setTotalWeight(BigDecimal totalWeight) { this.totalWeight = totalWeight; }
        
        public BigDecimal getSupportWeight() { return supportWeight; }
        public void setSupportWeight(BigDecimal supportWeight) { this.supportWeight = supportWeight; }
        
        public BigDecimal getOpposeWeight() { return opposeWeight; }
        public void setOpposeWeight(BigDecimal opposeWeight) { this.opposeWeight = opposeWeight; }
        
        public BigDecimal getAbstainWeight() { return abstainWeight; }
        public void setAbstainWeight(BigDecimal abstainWeight) { this.abstainWeight = abstainWeight; }
        
        public BigDecimal getWeightedSupportRate() { return weightedSupportRate; }
        public void setWeightedSupportRate(BigDecimal weightedSupportRate) { this.weightedSupportRate = weightedSupportRate; }
        
        public Boolean getApproved() { return approved; }
        public void setApproved(Boolean approved) { this.approved = approved; }
        
        public BigDecimal getConfidenceScore() { return confidenceScore; }
        public void setConfidenceScore(BigDecimal confidenceScore) { this.confidenceScore = confidenceScore; }
    }
}